﻿namespace JavaScript8000.Parser
{
    using System;
    using System.Collections.Generic;

    using JavaScript8000.Common;

    /// <summary>
    /// Represent the node of grammar tree.
    /// </summary>
    public class GrammarNode : ICloneable
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="GrammarNode"/> class.
        /// </summary>
        /// <param name="token">The token.</param>
        public GrammarNode(Token token)
        {
            this.Token = token;
            this.Children = new List<GrammarNode>();
            this.Parent = null;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GrammarNode"/> class.
        /// </summary>
        /// <param name="ruleName">Name of the rule.</param>
        public GrammarNode(string ruleName)
        {
            this.Value = ruleName;
            this.Children = new List<GrammarNode>();
            this.Token = null;
            this.Parent = null;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>
        /// The value.
        /// </value>
        public string Value { get; set; }

        /// <summary>
        /// Gets the value (token) of this node.
        /// </summary>
        public Token Token { get; set; }

        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        public GrammarNode Parent { get; set; }

        /// <summary>
        /// Gets the children.
        /// </summary>
        public List<GrammarNode> Children { get; private set; }

        /// <summary>
        /// Gets or sets my self clone.
        /// </summary>
        public GrammarNode MySelfClone { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="GrammarNode"/> is wasloop.
        /// </summary>
        /// <value>
        ///   <c>true</c> if wasloop; otherwise, <c>false</c>.
        /// </value>
        public bool Wasloop { get; set; }

        /// <summary>
        /// Makes me mom.
        /// </summary>
        public void MakeMeMom()
        {
            foreach (GrammarNode child in this.Children)
            {
                child.Parent = this;
                child.MakeMeMom();
            }
        }

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            GrammarNode clone = new GrammarNode(this.Value) { Token = this.Token, Parent = this.Parent, MySelfClone = this.MySelfClone, Wasloop = this.Wasloop };

            foreach (GrammarNode child in this.Children)
            {
                clone.Children.Add(this.GetClone(child, clone));
            }

            return clone;
        }

        /// <summary>
        /// Gets the clone.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="parent">The parent.</param>
        /// <returns></returns>
        private GrammarNode GetClone(GrammarNode node, GrammarNode parent)
        {
            GrammarNode clone = new GrammarNode(node.Value) { Token = node.Token, Parent = parent, MySelfClone = node.MySelfClone, Wasloop = node.Wasloop };

            foreach (GrammarNode child in node.Children)
            {
                clone.Children.Add(this.GetClone(child, clone));
            }

            return clone;
        }
    }
}
